home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1996 #1 / Amiga Plus CD - 1996 - No. 1.iso / pd / netz / xbtx_v1.1 / btxservice.cpp < prev    next >
C/C++ Source or Header  |  1995-09-26  |  55KB  |  2,365 lines

  1. /*
  2. **    $Id: BTXService.cpp 1.3 1995/09/26 16:48:58 olsen Exp olsen $
  3. **
  4. **    :ts=4
  5. */
  6.  
  7. /*
  8.  * Amiga changes copyright © 1995 by Olaf Barthel, All Rights Reserved
  9.  *
  10.  * Copyright (c) 1992, 1993 Arno Augustin, Frank Hoering, University of
  11.  * Erlangen-Nuremberg, Germany.
  12.  * All rights reserved.
  13.  *
  14.  * Redistribution and use in source and binary forms, with or without
  15.  * modification, are permitted provided that the following conditions
  16.  * are met:
  17.  * 1. Redistributions of source code must retain the above copyright
  18.  *    notice, this list of conditions and the following disclaimer.
  19.  * 2. Redistributions in binary form must reproduce the above copyright
  20.  *    notice, this list of conditions and the following disclaimer in the
  21.  *    documentation and/or other materials provided with the distribution.
  22.  * 3. All advertising materials mentioning features or use of this software
  23.  *    must display the following acknowledgement:
  24.  *    This product includes software developed by the University of
  25.  *    Erlangen-Nuremberg, Germany.
  26.  * 4. Neither the name of the University nor the names of its contributors
  27.  *    may be used to endorse or promote products derived from this software
  28.  *    without specific prior written permission.
  29.  *
  30.  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
  31.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  32.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
  33.  * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  34.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  35.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  36.  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  37.  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  38.  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  39.  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  40.  *
  41.  * This software has not been validated by the ``Bundesamt fuer Zulassungen in
  42.  * der Telekommunikation'' of the ``Deutsche Bundepost Telekom'' and thus
  43.  * must not be used for accessing the BTX-Network of the Telekom in Germany.
  44.  *
  45.  * Diese Software hat keine Zulassung durch das Bundesamt fuer Zulassungen in
  46.  * der Telekommunikation der Deutschen Bundespost Telekom und darf daher nicht
  47.  * am Netz der Deutschen Bundespost Telekom in Deutschland betrieben werden.
  48.  */
  49.  
  50. #define USE_PROTOCOL
  51.  
  52. #include "BTXService.hpp"
  53. #include <string.h>
  54. #include <ctype.h>
  55. #include <stdio.h>
  56.  
  57. #define LOG(x)        log()
  58. #define ERRLOG(x)    errlog()
  59.  
  60. /******************************************************************************/
  61.  
  62. BTXService::~BTXService()
  63. {
  64.     Close();
  65. }
  66.  
  67. BTXService::BTXService()
  68. {
  69.     memset(screen,0,sizeof(screen));
  70.     memset(&t,0,sizeof(t));
  71.     memset(&backup,0,sizeof(backup));
  72.     memset(data,0,sizeof(data));
  73.  
  74.     rows = fontheight = reachedEOF = 0;
  75.     pushback = -1;
  76.  
  77.     telefile = NULL;
  78.     teledownload = FALSE;
  79.     telename[0] = 0;
  80.     telemode = MODE_Unknown;
  81.  
  82. #ifdef USE_PROTOCOL
  83.     protocolfile = NULL;
  84. #endif
  85. }
  86.  
  87. VOID BTXService::Close(VOID)
  88. {
  89.     if(telefile)
  90.     {
  91.         fclose(telefile);
  92.  
  93.         telefile = NULL;
  94.     }
  95.  
  96. #ifdef USE_PROTOCOL
  97.     if(protocolfile)
  98.     {
  99.         fclose(protocolfile);
  100.         protocolfile = NULL;
  101.     }
  102. #endif
  103. }
  104.  
  105. LONG BTXService::Open(BTXDisplay *Disp,Application *Appl)
  106. {
  107.     AppDisplay    = Disp;
  108.     App            = Appl;
  109.  
  110.     Disp->MonitorData(&rows,&fontheight);
  111.  
  112. #ifdef USE_PROTOCOL
  113.     protocolfile = fopen("t:protocol","wb");
  114. #endif
  115.  
  116.     init_layer6();
  117.     return(0);
  118. }
  119.  
  120. int BTXService::ProcessInput(VOID)
  121. {
  122.     return(process_BTX_data());
  123. }
  124.  
  125. UBYTE BTXService::ConvertChar(int c,int s,int d)
  126. {
  127.    static UBYTE supp_map[96] =
  128.       { ' ', 0xa1, 0xa2, 0xa3, '$', 0xa5, '#', 0xa7, 0xa4, '`', '\"', 0xab,
  129.     0, 0, 0, 0, 0xb0, 0xb1, 0xb2, 0xb3, 0xd7, 0xb5, 0xb6, 0xb7, 0xf7,
  130.     '\'', '\"', 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0, 0x60, 0x27, 0, '~',
  131.     0xaf, 0, 0, 0x22, 0x22, 0xb0, 0, 0, 0x22, 0xb8, 0, 0xad, 0xb9, 0xae,
  132.     0xa9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xc6, 0, 0, 0, 0, 0,
  133.     0, 0, 0xd8, 0, 0, 0xfe, 0, 0, 0, 0, 0xe6, 0, 0, 0, 0, 0, 0, 0, 0xf8,
  134.     0, 0xdf, 0xde, 0, 0, 0 };
  135.  
  136.    static UBYTE diacritical_map[26*2][16] = {
  137.     { 0, 0xc0, 0xc1, 0xc2, 0xc3, 0, 0, 0, 0xc4, 0xc4, 0xc5, 0, 0, 0xc4, 0, 0 },
  138.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },     /* B */
  139.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0 },
  140.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },  /* D */
  141.     { 0, 0xc8, 0xc9, 0xca, 0, 0, 0, 0, 0xcb, 0xcb, 0, 0, 0, 0xcb, 0, 0 },
  142.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  143.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  144.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },  /* H */
  145.     { 0, 0xcc, 0xcd, 0xce, 0, 0, 0, 0, 0xcf, 0xcf, 0, 0, 0, 0xcf, 0, 0 },
  146.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  147.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  148.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  149.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  150.     { 0, 0, 0, 0, 0xd1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },  /* N */
  151.     { 0, 0xd2, 0xd3, 0xd4, 0xd5, 0, 0, 0, 0xd6, 0xd6, 0, 0, 0, 0xd6, 0, 0 },
  152.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  153.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  154.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  155.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  156.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* T */
  157.     { 0, 0xd9, 0xda, 0xdb, 0, 0, 0, 0, 0xdc, 0xdc, 0, 0, 0, 0xdc, 0, 0 },
  158.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  159.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  160.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* X */
  161.     { 0, 0, 0xdd, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  162.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  163.     { 0, 0xe0, 0xe1, 0xe2, 0xe3, 0, 0, 0, 0xe4, 0xe4, 0xe5, 0, 0, 0xe4, 0, 0 },
  164.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  165.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xe7, 0, 0, 0, 0 },  /* c */
  166.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  167.     { 0, 0xe8, 0xe9, 0xea, 0, 0, 0, 0, 0xeb, 0xeb, 0, 0, 0, 0xeb, 0, 0 },
  168.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  169.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  170.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* h */
  171.     { 0, 0xec, 0xed, 0xee, 0, 0, 0, 0, 0xef, 0xef, 0, 0, 0, 0xef, 0, 0 },
  172.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  173.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  174.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  175.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  176.     { 0, 0, 0, 0, 0xf1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* n */
  177.     { 0, 0xf2, 0xf3, 0xf4, 0xf5, 0, 0, 0, 0xf6, 0xf6, 0, 0, 0, 0xf6, 0, 0 },
  178.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  179.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  180.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  181.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  182.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* t */
  183.     { 0, 0xf9, 0xfa, 0xfb, 0, 0, 0, 0, 0xfc, 0xfc, 0, 0, 0, 0xfc, 0, 0 },
  184.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  185.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  186.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  187.     { 0, 0, 0xfd, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 0, 0, 0xff, 0, 0 },  /* y */
  188.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } };
  189.  
  190.     UBYTE Char;
  191.  
  192.     /* ASCII out of  1st supplementary set of mosaic characters */
  193.     if(s==SUP1 && c>=0x40 && c<=0x5f)
  194.         Char = (UBYTE)c;
  195.     else
  196.         Char = (UBYTE)' ';
  197.  
  198.     /* supplementary set of graphic characters */
  199.     if(s==SUPP && supp_map[c-0x20])
  200.         Char = (UBYTE)supp_map[c-0x20];
  201.     else
  202.     {
  203.         /* composed characters, diacritical marks (page 123) */
  204.         if(s==PRIM)
  205.         {
  206.             if(!d)
  207.                 Char = (UBYTE)c;  /* ASCII character */
  208.             else
  209.             {
  210.                 if(d>=0x40 && d<=0x4f)
  211.                 {
  212.                     if(c>=0x41 && c<=0x5a && diacritical_map[c-0x41][d&0xf])
  213.                         Char = (UBYTE)diacritical_map[c-0x41][d&0xf];
  214.                     else
  215.                     {
  216.                         if(c>=0x61 && c<=0x7a && diacritical_map[c-0x61+26][d&0xf])
  217.                             Char = (UBYTE)diacritical_map[c-0x61+26][d&0xf];
  218.                     }
  219.                 }
  220.             }
  221.         }
  222.     }
  223.  
  224.     return(Char);
  225. }
  226.  
  227. VOID BTXService::GetMatrix(UBYTE *Matrix,int *CursorX,int *CursorY)
  228. {
  229.     if(Matrix)
  230.     {
  231.         int x,y;
  232.  
  233.         memset(Matrix,' ',40 * 24);
  234.  
  235.         for(y = 0 ; y < rows ; y++)
  236.         {
  237.             for(x = 0 ; x < 40 ; x++)
  238.                 Matrix[y * 40 + x] = ConvertChar(screen[y][x].chr & 0x7f,screen[y][x].set,(screen[y][x].chr>>8) & 0x7f);
  239.         }
  240.     }
  241.  
  242.     if(CursorX)
  243.     {
  244.         if(t.cursor_on)
  245.             *CursorX = t.cursorx;
  246.         else
  247.             *CursorX = -1;
  248.     }
  249.  
  250.     if(CursorY)
  251.     {
  252.         if(t.cursor_on)
  253.             *CursorY = t.cursory;
  254.         else
  255.             *CursorY = -1;
  256.     }
  257. }
  258.  
  259. /******************************************************************************/
  260.  
  261. /* all 'page' references refer to 'FTZ 157 D2 E' */
  262.  
  263. #include "Control.h"
  264. #include "Font.h"
  265. #include "Attributes.h"
  266.  
  267. /*
  268.  * initialize layer6 variables
  269.  */
  270. void BTXService::init_layer6()
  271. {
  272.    int y;
  273.  
  274.    fontheight = 10;
  275.    rows = 24;
  276.    t.cursorx = t.cursory = 1;
  277.    t.wrap = 1;
  278.    t.service_break = 0;
  279.    t.scroll_area = 0;
  280.    t.scroll_impl = 1;
  281.    t.cursor_on = 0;
  282.    t.par_attr = 0;
  283.    t.par_fg = WHITE;
  284.    t.par_bg = TRANSPARENT;
  285.    for(y=0; y<24; y++)    AppDisplay->define_fullrow_bg(y, BLACK);
  286.    clearscreen();
  287.    default_sets();
  288. }
  289.  
  290. /*
  291.  * Read and process one layer6 code sequence.
  292.  * Returns 1 when DCT (terminate data collect 0x1a) is received, else 0.
  293.  */
  294.  
  295. int BTXService::process_BTX_data()
  296. {
  297.     int set, c1, c2, dct=0;
  298.  
  299.     c1 = layer2getc();
  300.  
  301.     if(c1>=0x00 && c1<=0x1f)
  302.         dct = primary_control_C0(c1);
  303.     else
  304.     {
  305.         if(c1>=0x80 && c1<=0x9f)
  306.             supplementary_control_C1(c1, 0);
  307.         else
  308.         {
  309.             if(t.sshift)
  310.                 set = t.G0123L[ t.sshift ];
  311.             else
  312.                 set = t.G0123L[ t.leftright[ (c1&0x80) >> 7 ] ];
  313.  
  314.             if( set == SUPP  &&  (c1 & 0x70) == 0x40 )     /* diacritical ??? */
  315.             {
  316.                 LOG(("diacritical mark %d\n", c1 & 0x0f));
  317.  
  318.                 c2 = layer2getc();
  319.  
  320.                 if(c2&0x60)
  321.                     c1 = (c1<<8) | c2;
  322.  
  323.                 t.sshift = 0;
  324.             }
  325.  
  326.             LOG(("OUTPUT 0x%02x '%c'\n", c1&0xff, isprint(c1&0xff) ? c1&0xff : '.'));
  327.  
  328.             output(c1);
  329.  
  330.             t.lastchar = c1;
  331.         }
  332.     }
  333.  
  334.     return dct;
  335. }
  336.  
  337.  
  338. /*
  339.  * get one byte from protocol layer 2.
  340.  */
  341.  
  342. int BTXService::layer2getc()
  343. {
  344.     LONG Value;
  345.     UBYTE c;
  346.  
  347.     /* is there a pushed back character ? */
  348.     if(pushback >= 0)
  349.     {
  350.         Value = App->DispatchDisplayEvent();
  351.  
  352.         if(Value == CHANNELERR_EOF)
  353.             reachedEOF = 1;
  354.  
  355.         c = (UBYTE)pushback;
  356.         pushback = -1;
  357.     }
  358.     else
  359.     {
  360.         while(!reachedEOF)
  361.         {
  362.             Value = App->DispatchEvent();
  363.  
  364.             switch(Value)
  365.             {
  366.                 case CHANNELERR_EOF:
  367.  
  368.                     reachedEOF = 1;
  369.                     return(US);
  370.  
  371.                 case CHANNELERR_Timeout:
  372.                 case CHANNELERR_Nothing:
  373.  
  374.                     App->WaitEvent();
  375.                     continue;
  376.             }
  377.  
  378.             if(Value < 0)
  379.                 reachedEOF = 1;
  380.             else
  381.             {
  382.                 c = (UBYTE)Value;
  383.  
  384. #ifdef USE_PROTOCOL
  385.                 if(protocolfile)
  386.                     fputc(c,protocolfile);
  387. #endif
  388.             }
  389.  
  390.             break;
  391.         }
  392.  
  393.         if(reachedEOF)
  394.             c = US;
  395.     }
  396.  
  397.     if(reachedEOF)
  398.         App->EventExit();
  399.  
  400.     LOG(("(%c %03x %2d/%2d %2x/%2x) (0x%02x)   ", t.serialmode ? 'S' : 'P',
  401.         t.serialmode ? screen[t.cursory-1][t.cursorx-1].attr : t.par_attr,
  402.         t.cursory, t.cursorx,
  403.         t.serialmode ? screen[t.cursory-1][t.cursorx-1].fg : t.par_fg,
  404.         t.serialmode ? screen[t.cursory-1][t.cursorx-1].bg : t.par_bg, c));
  405.  
  406.     return c;
  407. }
  408.  
  409.  
  410. /*
  411.  * unget character 'c'. Only one character of pushback is possible !
  412.  */
  413. void BTXService::layer2ungetc(int c)
  414. {
  415.     if(pushback < 0)
  416.     {
  417.         pushback = c;
  418.         LOG(("<-- character pushed back\n"));
  419.     }
  420.     else
  421.         ERRLOG(("XBTX: internal error: ungetc-buffer overflow !\n"));
  422. }
  423.  
  424.  
  425. /*
  426.  * initialize default character sets (page 113)
  427.  */
  428. void BTXService::default_sets()
  429. {
  430.    t.G0123L[G0] = PRIM;
  431.    t.G0123L[G1] = SUP2;
  432.    t.G0123L[G2] = SUPP;
  433.    t.G0123L[G3] = SUP3;
  434.    t.G0123L[ L] = L;       /* always L !!! (cannot be changed) */
  435.    t.leftright[0] = G0;
  436.    t.leftright[1] = G2;
  437.    t.sshift = 0;
  438.    t.save_left = G0;
  439.    t.prim = G0;
  440.    t.supp = G2;
  441. }
  442.  
  443. /*
  444.  * move the cursor, perform automatic wraparound (page 97)
  445.  *                    and implicite scrolling (page 101)
  446.  */
  447. void BTXService::move_cursor(int cmd, int y, int x)
  448. {
  449.    int up=0, down=0;
  450.  
  451.    /* erase old cursor */
  452.    if(t.cursor_on) AppDisplay->xcursor(t.cursorx-1, t.cursory-1);
  453.  
  454.    /* move & wrap */
  455.    switch(cmd) {
  456.       case APF:
  457.          if(++t.cursorx > 40)
  458.             if(t.wrap) { t.cursorx-=40; down=1; }
  459.             else         t.cursorx=40;
  460.          break;
  461.  
  462.       case APB:
  463.          if(--t.cursorx < 1)
  464.             if(t.wrap) { t.cursorx+=40; up=1; }
  465.             else         t.cursorx=1;
  466.          break;
  467.  
  468.       case APU:  up=1;           break;
  469.       case APD:  down=1;       break;
  470.       case APR:  t.cursorx=1;  break;
  471.  
  472.       case APA:
  473.          t.hold_mosaic = 0;
  474.          if(t.wrap) {    /* wrap !! (SKY-NET *200070000000004a#) */
  475.             if(x <    1)    { x += 40;    y--; }
  476.             if(x > 40)    { x -= 40;    y++; }
  477.             if(y <    1)      y += rows;
  478.             if(y > rows)  y -= rows;
  479.          }
  480.          else {
  481.             if(x <    1)    x =  1;
  482.             if(x > 40)    x = 40;
  483.             if(y <    1)    y =  1;
  484.             if(y > rows)  y = rows;
  485.          }
  486.  
  487.          t.cursorx=x;
  488.          t.cursory=y;
  489.          break;
  490.    }
  491.  
  492.    if(up) {
  493.       t.hold_mosaic = 0;
  494.       if(t.scroll_area && t.scroll_impl &&
  495.          t.cursory == t.scroll_upper)  scroll(0);
  496.       else
  497.          if(--t.cursory < 1)
  498.             if(t.wrap)    t.cursory += rows;
  499.             else        t.cursory  = 1;
  500.    }
  501.  
  502.    if(down) {
  503.       t.hold_mosaic = 0;
  504.       if(t.scroll_area && t.scroll_impl &&
  505.          t.cursory == t.scroll_lower)  scroll(1);
  506.       else
  507.          if(++t.cursory > rows)
  508.             if(t.wrap)    t.cursory -= rows;
  509.             else        t.cursory  = rows;
  510.    }
  511.  
  512.    /* draw new cursor */
  513.    if(t.cursor_on) AppDisplay->xcursor(t.cursorx-1, t.cursory-1);
  514. }
  515.  
  516.  
  517. /*
  518.  * process a code from the primary control set C0 (0x00 - 0x1f).
  519.  * Returns 1 when DCT is received, else 0.
  520.  */
  521.  
  522. int BTXService::primary_control_C0(int c1)    /* page 118, annex 6 */
  523. {
  524.    int c2, x, y;
  525.  
  526.    switch(c1) {
  527.  
  528.       case APB:
  529.          LOG(("APB active position back\n"));
  530.          move_cursor(APB);
  531.          break;
  532.  
  533.       case APF:
  534.          LOG(("APF active position forward\n"));
  535.          move_cursor(APF);
  536.          break;
  537.  
  538.       case APD:
  539.          LOG(("APD active position down\n"));
  540.          move_cursor(APD);
  541.          break;
  542.  
  543.       case APU:
  544.          LOG(("APU active position up\n"));
  545.          move_cursor(APU);
  546.          break;
  547.  
  548.       case CS:
  549.          LOG(("CS  clear screen\n"));
  550.          t.leftright[0] = t.save_left;
  551.          clearscreen();
  552.          break;
  553.  
  554.       case APR:
  555.          LOG(("APR active position return\n"));
  556.          move_cursor(APR);
  557.          break;
  558.  
  559.       case LS1:
  560.       case LS0:
  561.          c2 = (c1==LS1) ? 1 : 0;
  562.          LOG(("LS%d locking shift G%d left\n", c2, c2));
  563.          t.leftright[0] = c2;  /* G0 or G1 !! */
  564.          t.save_left = c2;
  565.          break;
  566.  
  567.       case CON:
  568.          LOG(("CON cursor on\n"));
  569.          if(!t.cursor_on) {
  570.             t.cursor_on = 1;
  571.             AppDisplay->xcursor(t.cursorx-1, t.cursory-1);
  572.          }
  573.          break;
  574.  
  575.       case RPT:
  576.          LOG(("RPT repeat last char\n"));
  577.          c2 = layer2getc() & 0x3f;
  578.          LOG(("    %d times\n", c2));
  579.          while(c2--)  output(t.lastchar);
  580.          break;
  581.  
  582.       case COF:
  583.          LOG(("COF cursor off\n"));
  584.          if(t.cursor_on) {
  585.             t.cursor_on = 0;
  586.             AppDisplay->xcursor(t.cursorx-1, t.cursory-1);
  587.          }
  588.          break;
  589.  
  590.       case CAN:
  591.          LOG(("CAN cancel\n"));
  592.          y = t.cursory-1;
  593.          screen[y][t.cursorx-1].chr = ' ';
  594.          screen[y][t.cursorx-1].set = PRIM;
  595.          for(x=t.cursorx; x<40; x++) {    /* clear to the right */
  596.             screen[y][x].chr    = ' ';
  597.             screen[y][x].set    = PRIM;
  598.             screen[y][x].mark    = 0;
  599.             screen[y][x].attr    = screen[y][t.cursorx-1].attr;
  600.             screen[y][x].fg     = screen[y][t.cursorx-1].fg;
  601.             screen[y][x].bg     = screen[y][t.cursorx-1].bg;
  602.          }
  603.          for(x=t.cursorx-1; x<40; x++)    redrawc(x+1, y+1);
  604.          break;
  605.  
  606.       case SS2:
  607.          LOG(("SS2 single shift G2 left\n"));
  608.          t.sshift = G2;
  609.          break;
  610.  
  611.       case ESC:
  612.          LOG(("ESC escape sequence\n"));
  613.          do_ESC();
  614.          break;
  615.  
  616.       case SS3:
  617.          LOG(("SS3 single shift G3 left\n"));
  618.          t.sshift = G3;
  619.          break;
  620.  
  621.       case APH:
  622.          LOG(("APH active position home\n"));
  623.          move_cursor(APA, 1, 1);
  624.          t.par_attr = 0;
  625.          t.par_fg = WHITE;
  626.          t.par_bg = TRANSPARENT;
  627.          break;
  628.  
  629.       case US:
  630.          LOG(("US  unit separator (or APA)\n"));
  631.          do_US();
  632.          break;
  633.  
  634.       default:
  635.          LOG(("??? unprocessed control character 0x%02x - ignored\n", c1));
  636.          if(c1 == DCT)    return 1;
  637.    }
  638.  
  639.    return 0;
  640. }
  641.  
  642.  
  643. /*
  644.  * process a code from the supplementary control set C1 (0x80 - 0x9f).
  645.  * 'fullrow' indicates attribute application to the complete row.
  646.  * Most codes advance active cursor position by one !
  647.  */
  648.  
  649. void BTXService::supplementary_control_C1(int c1, int fullrow)    /* page 121, annex 6 */
  650. {
  651.    int adv, mode = fullrow ? 2 : t.serialmode;
  652.  
  653.    switch(c1) {
  654.                      /* serial     parallel */
  655.       case 0x80:     /*  ABK       BKF      */
  656.       case 0x81:     /*  ANR       RDF      */
  657.       case 0x82:     /*  ANG       GRF      */
  658.       case 0x83:     /*  ANY       YLF      */
  659.       case 0x84:     /*  ANB       BLF      */
  660.       case 0x85:     /*  ANM       MGF      */
  661.       case 0x86:     /*  ANC       CNF      */
  662.       case 0x87:     /*  ANW       WHF      */
  663.          LOG(("set foreground to color #%d %s\n", t.clut*8+c1-0x80,
  664.          (mode==1) ? "(+ unload L set)" : ""));
  665.      set_attr(ATTR_FOREGROUND, 1, t.clut*8+c1-0x80, mode);
  666.      if(mode==1) {
  667.         t.leftright[0] = t.save_left;
  668.      }
  669.          break;
  670.  
  671.       case FSH:
  672.          LOG(("FSH flashing begin\n"));
  673.      /* set_attr(ATTR_FLASH, 1, 0, mode); */
  674.          break;
  675.  
  676.       case STD:
  677.          LOG(("STD flashing steady\n"));
  678.      /* set_attr(ATTR_FLASH, 0, 0, mode); */
  679.          break;
  680.  
  681.       case EBX:
  682.          LOG(("EBX end of window\n"));
  683.      /* set_attr(ATTR_WINDOW, 0, 0, mode); */
  684.          break;
  685.  
  686.       case SBX:
  687.          LOG(("SBX start of window\n"));
  688.      /* set_attr(ATTR_WINDOW, 1, 0, mode); */
  689.          break;
  690.  
  691.       case NSZ:
  692.          LOG(("NSZ normal size\n"));
  693.      set_attr(ATTR_NODOUBLE, 1, 0, mode);
  694.          break;
  695.  
  696.       case DBH:
  697.          LOG(("DBH double height\n"));
  698.      set_attr(ATTR_YDOUBLE, 1, 0, mode);
  699.          break;
  700.  
  701.       case DBW:
  702.          LOG(("DBW double width\n"));
  703.      set_attr(ATTR_XDOUBLE, 1, 0, mode);
  704.          break;
  705.  
  706.       case DBS:
  707.          LOG(("DBS double size\n"));
  708.      set_attr(ATTR_XYDOUBLE, 1, 0, mode);
  709.          break;
  710.  
  711.                      /* serial     parallel */
  712.       case 0x90:     /*  MBK       BKB      */
  713.       case 0x91:     /*  MSR       RDB      */
  714.       case 0x92:     /*  MSG       GRB      */
  715.       case 0x93:     /*  MSY       YLB      */
  716.       case 0x94:     /*  MSB       BLB      */
  717.       case 0x95:     /*  MSM       MGB      */
  718.       case 0x96:     /*  MSC       CNB      */
  719.       case 0x97:     /*  MSW       WHB      */
  720.      /* at fullrow control the parallel set is used ! */
  721.          LOG(("set %s to color #%d\n", (mode==1) ?
  722.          "mosaic foreground (+ invoke L set)" : "background",
  723.          t.clut*8+c1-0x90));
  724.      if(mode==1) {
  725.         set_attr(ATTR_FOREGROUND, 1, t.clut*8+c1-0x90, 1);
  726.         t.save_left = t.leftright[0];
  727.         t.leftright[0] = L;
  728.      }
  729.      else set_attr(ATTR_BACKGROUND, 1, t.clut*8+c1-0x90, mode);
  730.          break;
  731.  
  732.       case CDY:
  733.          LOG(("CDY conceal display\n"));
  734.      set_attr(ATTR_CONCEALED, 1, 0, mode);
  735.          break;
  736.  
  737.       case SPL:
  738.          LOG(("SPL stop lining\n"));
  739.      set_attr(ATTR_UNDERLINE, 0, 0, mode);
  740.          break;
  741.  
  742.       case STL:
  743.          LOG(("STL start lining\n"));
  744.      set_attr(ATTR_UNDERLINE, 1, 0, mode);
  745.          break;
  746.  
  747.       case CSI:
  748.          LOG(("CSI control sequence introducer\n"));
  749.          adv = do_CSI();
  750.          break;
  751.  
  752.       case 0x9c:
  753.          if(mode==1) {
  754.             LOG(("BBD black background\n"));
  755.         set_attr(ATTR_BACKGROUND, 1, t.clut*8+BLACK, 1);
  756.          } else {
  757.             LOG(("NPO normal polarity\n"));
  758.         set_attr(ATTR_INVERTED, 0, 0, mode);
  759.          }
  760.          break;
  761.  
  762.       case 0x9d:
  763.          if(mode==1) {
  764.             LOG(("NBD new background\n"));
  765.         set_attr(ATTR_BACKGROUND, 1,
  766.              screen[t.cursory-1][t.cursorx-1].fg, 1);
  767.          } else {
  768.             LOG(("IPO inverted polarity\n"));
  769.         set_attr(ATTR_INVERTED, 1, 0, mode);
  770.          }
  771.          break;
  772.  
  773.       case 0x9e:
  774.          if(mode==1) {
  775.             LOG(("HMS hold mosaic\n"));
  776.         t.hold_mosaic = 1;
  777.          } else {
  778.             LOG(("TRB transparent background\n"));
  779.         set_attr(ATTR_BACKGROUND, 1, TRANSPARENT, mode);
  780.          }
  781.          break;
  782.  
  783.       case 0x9f:
  784.          if(mode==1) {
  785.             LOG(("RMS release mosaic\n"));
  786.         t.hold_mosaic = 0;
  787.          } else {
  788.             LOG(("STC stop conceal\n"));
  789.         set_attr(ATTR_CONCEALED, 0, 0, mode);
  790.          }
  791.          break;
  792.    }
  793.  
  794.    /* serial attribute controls advance cursor 1 char forwards !  (page 90) */
  795.    if(mode==1 && (c1!=CSI || adv) )
  796.       if(t.hold_mosaic)  output(t.lastchar);  /* HMS/RMS (page 96) */
  797.       else                 move_cursor(APF);
  798. }
  799.  
  800.  
  801. void BTXService::do_US()  /* page 85/86 */
  802. {
  803.    static UBYTE TFI_string[] = { SOH, US, 0x20, 0x7f, 0x40, ETB };
  804.    int c2, c3, alphamosaic = 0;;
  805.  
  806.    /* implicite return from service break !!! (any US sequence !?!) */
  807.    if(t.service_break) {
  808.       t = backup;
  809.       move_cursor(APA, t.cursory, t.cursorx);
  810.    }
  811.  
  812.    for(;;)
  813.    {
  814.        c2 = layer2getc();
  815.        if(c2 != 0x1f)
  816.           break;
  817.    }
  818.  
  819.    switch(c2) {
  820.       case 0x20:  /* annex 7.3 */
  821.      LOG(("    TFI Terminal Facility Identifier\n"));
  822.      c3 = layer2getc();
  823.      if(c3==0x40) {
  824.         LOG(("       TFI request\n"));
  825.         write(TFI_string, 6);
  826.      }
  827.      else {
  828.         LOG(("       TFI echo 0x%02x\n", c3));
  829.         do {
  830.            c3 = layer2getc();
  831.            LOG(("       TFI echo 0x%02x\n", c3));
  832.         }
  833.         while(c3 & 0x20);  /* extension bit */
  834.      }
  835.      break;
  836.  
  837.       case 0x23:
  838.          LOG(("    define DRCS\n"));
  839.          do_DRCS();
  840.          break;
  841.  
  842.       case 0x26:
  843.          LOG(("    define color\n"));
  844.          do_DEFCOLOR();
  845.          break;
  846.  
  847.       case 0x2d:  /* page 155 */
  848.          LOG(("    define Format\n"));
  849.          do_DEFFORMAT();
  850.          break;
  851.  
  852.       case 0x2f:  /* page 157 */
  853.          LOG(("    Reset sequence\n"));
  854.          do_RESET();
  855.      alphamosaic = 1;
  856.          break;
  857.  
  858.       case 0x3e:  /* annex 7.4 */
  859.          LOG(("    telesoftware\n"));
  860.          do_Telesoftware();
  861.          alphamosaic = 0;
  862.          break;
  863.  
  864.       default:      /* APA active position addressing */
  865.      if(c2<0x40)  LOG(("    unknown US sequence\n"));
  866.      else {
  867.         alphamosaic = 1;
  868.         LOG(("    new row    %2d\n", c2 & 0x3f));
  869.         c3 = layer2getc();
  870.         LOG(("    new column %2d\n", c3 & 0x3f));
  871.         move_cursor(APA, c2 & 0x3f, c3 & 0x3f);
  872.         t.par_attr = 0;
  873.         t.par_fg = WHITE;
  874.         t.par_bg = TRANSPARENT;
  875.      }
  876.          break;
  877.    }
  878.  
  879.    /* VPDE = US x data. Each VPDE has to be followed by the next VPDE
  880.     * immediately (page 85). The alphamosaic VPDE is introduced by APA or
  881.     * by one of the reset functions ! Any remaining data (errors) after all
  882.     * other VPDE's has to be skipped (*17420101711a#).
  883.     */
  884.    if(!alphamosaic) {
  885.       while( (c2 = layer2getc()) != US )  LOG(("skipping to next US\n"));
  886.       LOG(("\n"));
  887.       layer2ungetc(US);
  888.    }
  889. }
  890.  
  891. void BTXService::do_ESC()
  892. {
  893.    int y, c2, c3, c4;
  894.  
  895.    c2 = layer2getc();
  896.  
  897.    switch(c2) {
  898.  
  899.       case 0x22:
  900.          LOG(("    invoke C1\n"));
  901.          c3 = layer2getc();
  902.          LOG(("       (%s)\n", c3==0x40 ? "serial" : "parallel"));
  903.      if(c3==0x40)  t.serialmode = 1;
  904.      else {
  905.         t.serialmode = 0;
  906.         t.leftright[0] = t.save_left;
  907.      }
  908.          break;
  909.  
  910.       case 0x23:
  911.          LOG(("    set attributes\n"));
  912.          c3 = layer2getc();
  913.          switch(c3) {
  914.             case 0x20:
  915.                LOG(("       full screen background\n"));
  916.                c4 = layer2getc();
  917.                LOG(("          color = %d\n",
  918.            c4==0x5e ? TRANSPARENT : t.clut*8+c4-0x50));
  919.            for(y=0; y<24; y++)
  920.               AppDisplay->define_fullrow_bg(y, c4==0x5e ?
  921.                     TRANSPARENT : t.clut*8+c4-0x50);
  922.                break;
  923.             case 0x21:
  924.                LOG(("       full row\n"));
  925.                c4 = layer2getc();
  926.            LOG(("          "));
  927.            supplementary_control_C1(c4+0x40, 1);
  928.                break;
  929.          }
  930.          break;
  931.  
  932.       case 0x28:
  933.  
  934.       case 0x29:
  935.       case 0x2a:
  936.       case 0x2b:
  937.          LOG(("    load G%d with\n", c2 - 0x28));
  938.          c3 = layer2getc();
  939.          switch(c3) {
  940.             case 0x40:
  941.                LOG(("       'primary graphic'\n"));
  942.                t.G0123L[c2 - 0x28] = PRIM;
  943.                t.prim = c2 - 0x28;
  944.                break;
  945.             case 0x62:
  946.                LOG(("       'supplementary graphic'\n"));
  947.                t.G0123L[c2 - 0x28] = SUPP;
  948.                t.supp = c2 - 0x28;
  949.                break;
  950.             case 0x63:
  951.                LOG(("       '2nd supplementary mosaic'\n"));
  952.                t.G0123L[c2 - 0x28] = SUP2;
  953.                break;
  954.             case 0x64:
  955.                LOG(("       '3rd supplementary mosaic'\n"));
  956.                t.G0123L[c2 - 0x28] = SUP3;
  957.                break;
  958.             case 0x20:
  959.            LOG(("       DRCS\n"));
  960.                c4 = layer2getc();
  961.                if(c4 != 0x40)  LOG(("HAEH  (ESC 0x%02x 0x20 0x%02x)\n", c2, c4));
  962.            else            LOG(("\n"));
  963.                t.G0123L[c2 - 0x28] = DRCS;
  964.                break;
  965.          }
  966.          break;
  967.  
  968.  
  969.       case 0x6e:
  970.          LOG(("    LS2 locking shift G2 left\n"));
  971.          t.leftright[0] = G2;
  972.      t.save_left = G2;
  973.          break;
  974.  
  975.       case 0x6f:
  976.          LOG(("    LS3 locking shift G3 left\n"));
  977.          t.leftright[0] = G3;
  978.      t.save_left = G3;
  979.          break;
  980.  
  981.       case 0x7c:
  982.          LOG(("    LS3R locking shift G3 right\n"));
  983.          t.leftright[1] = G3;
  984.          break;
  985.  
  986.       case 0x7d:
  987.          LOG(("    LS2R locking shift G2 right\n"));
  988.          t.leftright[1] = G2;
  989.          break;
  990.  
  991.       case 0x7e:
  992.          LOG(("    LS1R locking shift G1 right\n"));
  993.          t.leftright[1] = G1;
  994.          break;
  995.    }
  996. }
  997.  
  998.  
  999. /*
  1000.  * Process one control sequence. Return whether or not the cursor position
  1001.  * has to be advanced by one char (in case of serialmode).
  1002.  *
  1003.  * Anscheinend sollen nur die FLASH-controls den Cursor eins weiterstellen -
  1004.  * steht zwar nirgends, sieht aber am besten aus !!!
  1005.  */
  1006.  
  1007. int BTXService::do_CSI()
  1008. {
  1009.    int c2, c3, upper, lower;
  1010.  
  1011.    c2 = layer2getc();
  1012.    if(c2 == 0x42) {
  1013.       LOG(("    STC stop conceal\n"));
  1014.       set_attr(ATTR_CONCEALED, 0, 0, t.serialmode);
  1015.       return 0;
  1016.    }
  1017.  
  1018.    LOG(("\n"));
  1019.    c3 = layer2getc();
  1020.  
  1021.    /* protection only available as fullrow controls ?? (page 135) */
  1022.    if(c2 == 0x31 && c3 == 0x50) {
  1023.       LOG(("       PMS protected mode start\n"));
  1024.       set_attr(ATTR_PROTECTED, 1, 0, 2);
  1025.       return 0;
  1026.    }
  1027.    if(c2 == 0x31 && c3 == 0x51) {
  1028.       LOG(("       PMC protected mode cancel\n"));
  1029.       set_attr(ATTR_PROTECTED, 0, 0, 2);
  1030.       return 0;
  1031.    }
  1032.    if(c2 == 0x32 && c3 == 0x53) {
  1033.       LOG(("       MMS marked mode start\n"));
  1034.       /* set_attr(ATTR_MARKED, 1, 0, t.serialmode); */
  1035.       return 0;
  1036.    }
  1037.    if(c2 == 0x32 && c3 == 0x54) {
  1038.       LOG(("       MMT marked mode stop\n"));
  1039.       /* set_attr(ATTR_MARKED, 0, 0, t.serialmode); */
  1040.       return 0;
  1041.    }
  1042.  
  1043.    switch(c3) {
  1044.  
  1045.       case 0x40:
  1046.          LOG(("       invoke CLUT%d\n", c2 - 0x2f));
  1047.  
  1048.  
  1049.      t.clut = c2 - 0x30;
  1050.          return 0;
  1051.  
  1052.       case 0x41:
  1053.          switch(c2) {
  1054.             case 0x30:
  1055.                LOG(("       IVF inverted flash\n"));
  1056.                return 1;
  1057.             case 0x31:
  1058.                LOG(("       RIF reduced intesity flash\n"));
  1059.                return 1;
  1060.             case 0x32:
  1061.             case 0x33:
  1062.             case 0x34:
  1063.                LOG(("       FF%c fast flash %c\n", c2-1, c2-1));
  1064.                return 1;
  1065.             case 0x35:
  1066.                LOG(("       ICF increment flash\n"));
  1067.                return 1;
  1068.             case 0x36:
  1069.                LOG(("       DCF decrement flash\n"));
  1070.                return 1;
  1071.          }
  1072.          break;
  1073.  
  1074.       case 0x60:
  1075.          switch(c2) {
  1076.             case 0x30:
  1077.                LOG(("       SCU explicit scroll up\n"));
  1078.            if(t.scroll_area) scroll(1);
  1079.                return 0;
  1080.             case 0x31:
  1081.                LOG(("       SCD explicit scroll down\n"));
  1082.            if(t.scroll_area) scroll(0);
  1083.  
  1084.                return 0;
  1085.             case 0x32:
  1086.                LOG(("       AIS activate implicite scrolling\n"));
  1087.            t.scroll_impl = 1;
  1088.                return 0;
  1089.             case 0x33:
  1090.                LOG(("       DIS deactivate implicite scrolling\n"));
  1091.            t.scroll_impl = 0;
  1092.                return 0;
  1093.          }
  1094.          break;
  1095.  
  1096.       default:    /* definition of scrolling area (page 137) */
  1097.      upper = c2 & 0x0f;
  1098.      if(c3>=0x30 && c3<=0x39)  upper = upper*10 + (c3&0x0f);
  1099.      LOG(("       upper row: %2d\n", upper));
  1100.      if(c3>=0x30 && c3<=0x39)  { c3 = layer2getc(); LOG(("\n")); }
  1101.  
  1102.      if(c3!=0x3b)  ERRLOG(("XBTX: scrolling area - protocol !\n"));
  1103.  
  1104.      lower = layer2getc() & 0x0f;
  1105.      LOG(("\n"));
  1106.      c3 = layer2getc();
  1107.      if(c3>=0x30 && c3<=0x39)  lower = lower*10 + (c3&0x0f);
  1108.      LOG(("       lower row: %2d", lower));
  1109.      if(c3>=0x30 && c3<=0x39)  { LOG(("\n")); c3=layer2getc(); LOG(("    ")); }
  1110.  
  1111.      if(c3==0x55) {
  1112.         LOG(("   CSA create scrolling area\n"));
  1113.         if(upper>=2 && lower<rows && lower>=upper) {
  1114.            t.scroll_upper = upper;
  1115.            t.scroll_lower = lower;
  1116.            t.scroll_area = 1;
  1117.         }
  1118.      }
  1119.      if(c3==0x56) {
  1120.         LOG(("   CSD delete scrolling area\n"));
  1121.         t.scroll_area = 0;
  1122.      }
  1123.          return 0;
  1124.    }
  1125.    return 0;
  1126. }
  1127.  
  1128.  
  1129. void BTXService::do_DRCS()     /* (page 139ff) */
  1130. {
  1131.    int c3, c4, c5, c6, c7, c8;
  1132.  
  1133.    c3 = layer2getc();
  1134.    if(c3 == 0x20) {
  1135.       LOG(("       DRCS header unit\n"));
  1136.       c4 = layer2getc();
  1137.       if(c4==0x20 || c4==0x28) {
  1138.      LOG(("          %s existing DRCS\n", (c4==0x20) ? "keep" : "delete"));
  1139.  
  1140.      if(c4==0x28)  AppDisplay->free_DRCS();
  1141.      c5 = layer2getc();
  1142.       } else c5 = c4;
  1143.       if(c5 == 0x20) {
  1144.      LOG(("\n"));
  1145.      c6 = layer2getc();
  1146.       } else c6 = c5;
  1147.       if(c6 == 0x40) {
  1148.      LOG(("\n"));
  1149.      c7 = layer2getc();
  1150.       } else c7 = c6;
  1151.  
  1152.       switch(c7 & 0xf) {
  1153.          case 6:
  1154.         LOG(("          12x12 pixel\n"));
  1155.         t.drcs_w = 12;
  1156.         t.drcs_h = 12;
  1157.         break;
  1158.      case 7:
  1159.         LOG(("          12x10 pixel\n"));
  1160.         t.drcs_w = 12;
  1161.         t.drcs_h = 10;
  1162.         break;
  1163.      case 10:
  1164.         LOG(("          6x12 pixel\n"));
  1165.         t.drcs_w = 6;
  1166.         t.drcs_h = 12;
  1167.         break;
  1168.      case 11:
  1169.         LOG(("          6x10 pixel\n"));
  1170.         t.drcs_w = 6;
  1171.         t.drcs_h = 10;
  1172.         break;
  1173.      case 12:
  1174.         LOG(("          6x5 pixel\n"));
  1175.         t.drcs_w = 6;
  1176.         t.drcs_h = 5;
  1177.         break;
  1178.      case 15:
  1179.         LOG(("          6x6 pixel\n"));
  1180.         t.drcs_w = 6;
  1181.         t.drcs_h = 6;
  1182.         break;
  1183.       }
  1184.  
  1185.       c8 = layer2getc();
  1186.       LOG(("          %d bit/pixel\n", c8 & 0xf));
  1187.       t.drcs_bits = c8 & 0xf;
  1188.       t.drcs_step = (t.drcs_h>=10 && t.drcs_w*t.drcs_bits==24)    ?  2 : 1;
  1189.    }
  1190.    else {
  1191.       LOG(("       DRCS pattern transfer unit (char: 0x%02x)\n", c3));
  1192.       do_DRCS_data(c3);
  1193.    }
  1194. }
  1195.  
  1196.  
  1197. /*
  1198.  * load and define dynamic characters, first character is 'c'.
  1199.  * more than one bitplane of a character may be loaded simultaneously !
  1200.  */
  1201.  
  1202. void BTXService::do_DRCS_data(int c)
  1203. {
  1204.    int c4, i, n, planes=0, planemask=0, byte=0;
  1205.    int maxbytes, start = c;
  1206.  
  1207.    maxbytes = 2*t.drcs_h;
  1208.    if(t.drcs_h<10)    maxbytes *= 2;
  1209.  
  1210.    memset(data,0,sizeof(data));
  1211.  
  1212.    do {
  1213.       c4 = layer2getc();
  1214.  
  1215.       switch(c4) {
  1216.          case 0x20:  /* S-bytes */
  1217.          case 0x2f:
  1218.         LOG(("          fill rest of char with %d\n", c4 & 1));
  1219.         for(; byte<maxbytes; byte++)
  1220.            for(n=0; n<4; n++)
  1221.               if(planemask & (1<<n)) data[n][byte] = (UBYTE)((c4==0x20) ? 0 : 0xff);
  1222.         break;
  1223.      case 0x21:
  1224.      case 0x22:
  1225.      case 0x23:
  1226.      case 0x24:
  1227.      case 0x25:
  1228.      case 0x26:
  1229.      case 0x27:
  1230.      case 0x28:
  1231.      case 0x29:
  1232.      case 0x2a:
  1233.         LOG(("          repeat last row %d times\n", c4 & 0xf));
  1234.         if(byte&1) byte++;     /* pad to full row (assume 0) */
  1235.             for(i=0; i<(c4 & 0xf); i++) {
  1236.            for(n=0; n<4; n++)
  1237.               if(planemask & (1<<n)) {
  1238.              data[n][byte]     = (UBYTE)(byte ? data[n][byte-2] : 0);
  1239.              data[n][byte+1] = (UBYTE)(byte ? data[n][byte-2+1] : 0);
  1240.              if(t.drcs_h<10) {
  1241.             data[n][byte+2] = (UBYTE)(byte ? data[n][byte-2] : 0);
  1242.             data[n][byte+3] = (UBYTE)(byte ? data[n][byte-2+1] : 0);
  1243.              }
  1244.           }
  1245.            byte += 2;
  1246.            if(t.drcs_h<10)    byte += 2;
  1247.         }
  1248.             break;
  1249.      case 0x2c:
  1250.      case 0x2d:
  1251.         LOG(("          full row %d\n", c4 & 1));
  1252.         if(byte&1) byte++;     /* pad to full row (assume 0) */
  1253.             for(n=0; n<4; n++)
  1254.            if(planemask & (1<<n)) {
  1255.           data[n][byte]   = (UBYTE)((c4==0x2c) ? 0 : 0xff);
  1256.           data[n][byte+1] = (UBYTE)((c4==0x2c) ? 0 : 0xff);
  1257.           if(t.drcs_h<10) {
  1258.              data[n][byte+2] = (UBYTE)((c4==0x2c) ? 0 : 0xff);
  1259.              data[n][byte+3] = (UBYTE)((c4==0x2c) ? 0 : 0xff);
  1260.           }
  1261.            }
  1262.             byte += 2;
  1263.         if(t.drcs_h<10)  byte += 2;
  1264.             break;
  1265.      case 0x2e:
  1266.         LOG(("          fill rest of char with last row\n"));
  1267.         if(byte&1) byte++;     /* pad to full row (assume 0) */
  1268.             while(byte<maxbytes) {
  1269.            for(n=0; n<4; n++)
  1270.               if(planemask & (1<<n)) {
  1271.              data[n][byte]     = data[n][byte-2];
  1272.              data[n][byte+1] = data[n][byte-2+1];
  1273.           }
  1274.            byte += 2;
  1275.         }
  1276.             break;
  1277.  
  1278.          case 0x30:  /* B-bytes */
  1279.          case 0x31:
  1280.          case 0x32:
  1281.          case 0x33:
  1282.         if(byte) {
  1283.            LOG(("          new plane ahead - filling up\n"));
  1284.            byte = maxbytes;   /* pad to full plane */
  1285.            layer2ungetc(c4);
  1286.         }
  1287.         else {
  1288.            LOG(("          start of pattern block (plane %d)\n", c4 & 0xf));
  1289.            for(i=0; i<2*FONT_HEIGHT; i++)  data[c4 & 0xf][i] = 0;
  1290.            planemask |= 1 << (c4 & 0xf);
  1291.         }
  1292.         break;
  1293.  
  1294.      default:
  1295.             if(c4<0x20 || c4>0x7f) {
  1296.            LOG(("          end of pattern data\n"));
  1297.            layer2ungetc(c4);
  1298.            if(byte)  byte = maxbytes;
  1299.         }
  1300.  
  1301.  
  1302.         else {     /* D-bytes */
  1303.            LOG(("          pattern data\n"));
  1304.            if(t.drcs_w==6) {   /* low res */
  1305.           for(n=0; n<4; n++)
  1306.              if(planemask & (1<<n))  {
  1307.             data[n][byte] =
  1308.                  (UBYTE)(((c4&32)?0x30:0) | ((c4&16)?0x0c:0) | ((c4&8)?0x03:0));
  1309.             data[n][byte+1] =
  1310.                  (UBYTE)(((c4&4)?0x30:0) | ((c4&2)?0x0c:0) | ((c4&1)?0x03:0));
  1311.              }
  1312.           byte += 2;
  1313.            }
  1314.            else {
  1315.           for(n=0; n<4; n++)
  1316.              if(planemask & (1<<n))  data[n][byte] = (UBYTE)(c4 & 0x3f);
  1317.           byte++;
  1318.            }
  1319.  
  1320.            if(!(byte&1) && t.drcs_h<10) {  /* duplicate row ? */
  1321.           for(n=0; n<4; n++)
  1322.                  if(planemask & (1<<n)) {
  1323.             data[n][byte]    = data[n][byte-2];
  1324.             data[n][byte+1] = data[n][byte-2+1];
  1325.              }
  1326.           byte += 2;
  1327.            }
  1328.         }
  1329.         break;
  1330.  
  1331.       } /* switch */
  1332.  
  1333.       if(byte == maxbytes) {  /* plane is complete */
  1334.      for(n=0; n<4; n++)  if(planemask & (1<<n))  planes++;
  1335.      planemask = 0;
  1336.      byte = 0;
  1337.      if(planes == t.drcs_bits) {  /* DRC is complete */
  1338.         log_DRC(c, t.drcs_bits);
  1339.         AppDisplay->define_raw_DRC(c, &data[0][0], t.drcs_bits);
  1340.         planes = 0;
  1341.         c += t.drcs_step;
  1342.      }
  1343.       }
  1344.  
  1345.  
  1346.    } while(c4>=0x20 && c4<=0x7f);
  1347.  
  1348.    update_DRCS_display(start, c, t.drcs_step);
  1349. }
  1350.  
  1351.  
  1352. /*
  1353.  * pretty print the received character to the LOG file
  1354.  */
  1355. void BTXService::log_DRC(int c, int bits)
  1356. {
  1357.    int n, i, j, k;
  1358.  
  1359.    LOG(("\n                      DRC # 0x%2x\n", c));
  1360.    for(n=0; n<bits; n++) {
  1361.       LOG(("                      (plane %d)\n", n));
  1362.       LOG(("                      --------------------------\n"));
  1363.       for(j=0; j<fontheight; j++) {
  1364.      LOG(("                      |"));
  1365.      for(k=0; k<2; k++)
  1366.         for(i=5; i>=0; i--)
  1367.            if(data[n][j*2+k] & (1<<i)) LOG(("* "));
  1368.            else                        LOG(("  "));
  1369.      LOG(("|\n"));
  1370.       }
  1371.       LOG(("                      --------------------------\n\n"));
  1372.    }
  1373. }
  1374.  
  1375.  
  1376. /*
  1377.  * load and define dynamic colors.
  1378.  */
  1379. void BTXService::do_DEFCOLOR()    /* (page 150ff) */
  1380. {
  1381.    int c3, c4, c5, c6, c7, index, r, g, b;
  1382.  
  1383.    c3 = layer2getc();
  1384.  
  1385.    switch(c3) {
  1386.  
  1387.  
  1388.       case 0x20:   /*  US 0x26 0x20 <ICT> <SUR> <SCM>  */
  1389.          LOG(("       color header unit\n"));
  1390.          t.col_modmap = 1;      /* by default modify colormap */
  1391.          c4 = layer2getc();
  1392.          if((c4 & 0xf0) == 0x20) {
  1393.         if(c4!=0x20 && c4!=0x22) {
  1394.            LOG(("*** <ICT>: bad value !\n"));
  1395.            ERRLOG(("XBTX: do_DEFCOLOR(): ICT1 = 0x%02x\n", c4));
  1396.         }
  1397.             LOG(("          <ICT>: load %s\n", c4==0x20 ? "colormap" : "DCLUT"));
  1398.         t.col_modmap = (c4==0x20);
  1399.             c5 = layer2getc();
  1400.          } else c5 = c4;
  1401.          if((c5 & 0xf0) == 0x20) {
  1402.             LOG(("          <ICT>: (unit %d)\n", c5&0xf));
  1403.         if(c5!=0x20) {
  1404.            LOG(("*** <ICT>: bad value !\n"));
  1405.            ERRLOG(("XBTX: do_DEFCOLOR(): ICT2 = 0x%02x\n", c5));
  1406.         }
  1407.             c6 = layer2getc();
  1408.          } else c6 = c5;
  1409.          if((c6 & 0xf0) == 0x30) {
  1410.             LOG(("          <SUR>: %d bits\n", c6&0xf));
  1411.         if(c6!=0x34 && c6!=0x35) {
  1412.            LOG(("*** <SUR>: bad value !\n"));
  1413.            ERRLOG(("XBTX: do_DEFCOLOR(): SUR = 0x%02x\n", c6));
  1414.         }
  1415.             c7 = layer2getc();
  1416.          } else c7 = c6;
  1417.          if((c7 & 0xf0) == 0x40) {
  1418.             LOG(("          <SCM>: 0x%02x\n", c7));
  1419.         if(c7!=0x40 && c7!=0x41) {
  1420.            LOG(("*** <SCM>: bad value !\n"));
  1421.            ERRLOG(("XBTX: do_DEFCOLOR(): SCM = 0x%02x\n", c7));
  1422.         }
  1423.          } else {
  1424.             LOG(("          default header\n"));
  1425.             layer2ungetc(c7);
  1426.          }
  1427.          break;
  1428.  
  1429.       case 0x21:
  1430.          LOG(("       color reset unit\n"));
  1431.      AppDisplay->default_colors();
  1432.          break;
  1433.  
  1434.       default:
  1435.          LOG(("       color transfer unit  (1.Stelle: %d)\n", c3&0xf));
  1436.      index = c3&0xf;
  1437.          c4 = layer2getc();
  1438.          if((c4 & 0xf0) == 0x30) { /* c3 zehner, c4 einer */
  1439.             LOG(("                            (2.Stelle: %d)\n", c4&0xf));
  1440.         index = (c3&0xf)*10 + (c4&0xf);
  1441.             c5 = layer2getc();
  1442.          } else c5 = c4;
  1443.  
  1444.      if(t.col_modmap) {  /* load colormap */
  1445.         while(c5>=0x40 && c5<=0x7f) {
  1446.            LOG(("          color #%2d:  R G B\n", index));
  1447.            c6 = layer2getc();
  1448.            r = (c5&0x20)>>2 | (c5&0x04)    | (c6&0x20)>>4 | (c6&0x04)>>2;
  1449.            g = (c5&0x10)>>1 | (c5&0x02)<<1 | (c6&0x10)>>3 | (c6&0x02)>>1;
  1450.            b = (c5&0x08)    | (c5&0x01)<<2 | (c6&0x08)>>2 | (c6&0x01);
  1451.  
  1452.            LOG(("                      %1x %1x %1x\n", r, g, b));
  1453.            if(index>=16 && index<=31)  AppDisplay->define_color(index++, r, g, b);
  1454.            c5 = layer2getc();
  1455.         }
  1456.      }
  1457.      else {  /* load DCLUT */
  1458.         while(c5>=0x40 && c5<=0x7f) {
  1459.            LOG(("          DCLUT[%2d] = %2d\n", index, c5&0x1f));
  1460.            if(index>=0 && index<=3)  AppDisplay->define_DCLUT(index++, c5&0x1f);
  1461.            c5 = layer2getc();
  1462.         }
  1463.      }
  1464.  
  1465.      LOG(("          end of color data\n"));
  1466.          layer2ungetc(c5);
  1467.          break;
  1468.    }
  1469. }
  1470.  
  1471.  
  1472. void BTXService::do_DEFFORMAT()   /* format designation  (page 155) */
  1473. {
  1474.    int c3, c4;
  1475.  
  1476.    rows = 24;
  1477.    fontheight = 10;
  1478.    t.wrap  = 1;
  1479.  
  1480.    c3 = layer2getc();
  1481.    if((c3&0xf0) == 0x40) {
  1482.       switch(c3) {
  1483.          case 0x41:
  1484.             LOG(("       40 columns by 24 rows\n"));
  1485.         break;
  1486.          case 0x42:
  1487.         LOG(("       40 columns by 20 rows\n"));
  1488.         rows = 20;
  1489.         fontheight = 12;
  1490.         break;
  1491.          default:
  1492.         LOG(("       unrecognized format (using default)\n"));
  1493.         break;
  1494.       }
  1495.       c4 = layer2getc();
  1496.    }
  1497.    else c4 = c3;
  1498.  
  1499.    if((c4&0xf0) == 0x70) {
  1500.       LOG(("       wraparound %s\n", (c3&1) ? "inactive" : "active"));
  1501.       t.wrap = (c3 == 0x70) ? 1 : 0;
  1502.    }
  1503.    else {
  1504.       LOG(("       default format\n"));
  1505.       layer2ungetc(c4);
  1506.    }
  1507. }
  1508.  
  1509.  
  1510. void BTXService::do_RESET()  /* reset functions  (page 157) */
  1511. {
  1512.    int y, c3, c4;
  1513.  
  1514.    c3 = layer2getc();
  1515.  
  1516.    switch(c3) {
  1517.  
  1518.       case 0x40:   /* (page 158) */
  1519.          LOG(("       service break to row\n"));
  1520.          c4 = layer2getc();
  1521.          LOG(("          #%d\n", c4 & 0x3f));
  1522.          backup = t;  /* structure copy */
  1523.          t.leftright[0] = t.prim;  /* PFUSCH !!! */
  1524.          t.leftright[1] = t.supp;
  1525.      t.save_left = t.prim;
  1526.          t.wrap = 0;
  1527.      t.cursor_on = 0;
  1528.      move_cursor(APA, c4 & 0x3f, 1);
  1529.          t.serialmode = 1;
  1530.      t.clut = 0;
  1531.      t.service_break = 1;
  1532.          break;
  1533.  
  1534.       case 0x41:
  1535.       case 0x42:
  1536.          LOG(("       defaults (%s C1)\n", c3&1 ? "serial" : "parallel"));
  1537.          default_sets();
  1538.          t.serialmode = c3 & 1;
  1539.          t.wrap = 1;
  1540.      t.cursor_on = 0;
  1541.      rows = 24;
  1542.      fontheight = 10;
  1543.      for(y=0; y<24; y++)  AppDisplay->define_fullrow_bg(y, BLACK);
  1544.          clearscreen();  /* clearscr resets CLUT, par_attr, cursor pos */
  1545.          break;
  1546.  
  1547.       case 0x43:
  1548.       case 0x44:
  1549.          LOG(("       limited defaults (%s C1)\n", c3&1 ? "serial":"parallel"));
  1550.          default_sets();
  1551.          t.serialmode = c3 & 1;
  1552.          break;
  1553.  
  1554.       case 0x4f:
  1555.          LOG(("       reset to previous state\n"));
  1556.          t = backup;
  1557.      move_cursor(APA, t.cursory, t.cursorx);
  1558.          break;
  1559.    }
  1560. }
  1561.  
  1562.  
  1563. /*
  1564.  * set/reset parallel, serial or fullrow attributes (+ set/delete markers)
  1565.  * (mode: 0=parallel, 1=serial, 2=fullrow)
  1566.  *
  1567.  * MARKER:    (page 91 / annex 1, page 29)
  1568.  *
  1569.  *     parallel: (set in output())
  1570.  *        set wherever an attr is changed
  1571.  *        set at attr changes in writing a continuous string
  1572.  *        delete existing markers in overwritten part of "
  1573.  *        delete when printing and attrs do not change
  1574.  *
  1575.  *     serial:   (set here)
  1576.  *        set at this position
  1577.  */
  1578.  
  1579. void BTXService::set_attr(int a, int set, int col, int mode)
  1580. {
  1581.    int x, y = t.cursory-1, refresh, mattr = a;
  1582.  
  1583.    /* set fullrow background */
  1584.    if(mode==2 && a==ATTR_BACKGROUND) {
  1585.       AppDisplay->define_fullrow_bg(y, col);
  1586.       return;
  1587.    }
  1588.  
  1589.    if(a & ATTR_ANYSIZE)  mattr = ATTR_SIZE;
  1590.  
  1591.    /* serial mode controls set a marker */
  1592.    if(mode==1)    screen[y][t.cursorx-1].mark |= mattr;
  1593.  
  1594.    /* serial/fullrow controls apply to parts of the row */
  1595.    if(mode) {  /* serial || fullrow */
  1596.  
  1597.       /* receiption of serial DBS/DBH in last row of scrolling area        */
  1598.       /* forces a scroll up + a cursor up before writing (page 101) */
  1599.       if( (t.service_break || !(screen[y][0].attr & ATTR_PROTECTED))  &&
  1600.      (a==ATTR_YDOUBLE || a==ATTR_XYDOUBLE) &&
  1601.      t.scroll_area && t.cursory==t.scroll_lower) {
  1602.      scroll(1);
  1603.      move_cursor(APU);
  1604.      y = t.cursory-1;
  1605.       }
  1606.  
  1607.       x = (mode==2) ? 0 : t.cursorx-1;
  1608.  
  1609.       do {
  1610.      refresh = 0;
  1611.  
  1612.      /* fullrow controls delete the marker in the complete row */
  1613.      if(mode==2)  screen[y][x].mark &= ~mattr;
  1614.  
  1615.      if( t.service_break || !(screen[y][x].attr & ATTR_PROTECTED) ||
  1616.         (a==ATTR_PROTECTED && set==0) ) {
  1617.         switch(a) {
  1618.            case ATTR_NODOUBLE:
  1619.               if(screen[y][x].attr & (ATTR_XDOUBLE|ATTR_YDOUBLE))
  1620.              refresh = 1;
  1621.           screen[y][x].attr &= ~(ATTR_XDOUBLE|ATTR_YDOUBLE);
  1622.           break;
  1623.            case ATTR_XYDOUBLE:
  1624.           if((screen[y][x].attr & (ATTR_XDOUBLE|ATTR_YDOUBLE)) !=
  1625.              (ATTR_XDOUBLE|ATTR_YDOUBLE) )    refresh = 1;
  1626.           screen[y][x].attr |= (ATTR_XDOUBLE|ATTR_YDOUBLE);
  1627.           break;
  1628.            case ATTR_XDOUBLE:
  1629.           if((screen[y][x].attr & (ATTR_XDOUBLE|ATTR_YDOUBLE)) !=
  1630.              ATTR_XDOUBLE )  refresh = 1;
  1631.           screen[y][x].attr &= ~ATTR_YDOUBLE;
  1632.           screen[y][x].attr |= ATTR_XDOUBLE;
  1633.           break;
  1634.            case ATTR_YDOUBLE:
  1635.           if((screen[y][x].attr & (ATTR_XDOUBLE|ATTR_YDOUBLE)) !=
  1636.              ATTR_YDOUBLE )  refresh = 1;
  1637.           screen[y][x].attr &= ~ATTR_XDOUBLE;
  1638.           screen[y][x].attr |= ATTR_YDOUBLE;
  1639.           break;
  1640.            case ATTR_FOREGROUND:
  1641.           if(screen[y][x].fg!=col && screen[y][x].chr!=' ') refresh=1;
  1642.           screen[y][x].fg = (UBYTE)col;
  1643.           break;
  1644.            case ATTR_BACKGROUND:
  1645.           if(screen[y][x].bg != col)  refresh = 1;
  1646.           screen[y][x].bg = (UBYTE)col;
  1647.           break;
  1648.  
  1649.            default:
  1650.           if( ((screen[y][x].attr & a)>0) != set )    refresh = 1;
  1651.           if(set)  screen[y][x].attr |= a;
  1652.           else       screen[y][x].attr &= ~a;
  1653.           break;
  1654.         } /* switch */
  1655.  
  1656.         if(refresh)  redrawc(x+1, y+1);
  1657.  
  1658.         /* (DBH/DBS chars must not cross borders of a protected area) */
  1659.         if(a==ATTR_PROTECTED && y && realattr(y, x+1, ATTR_YDOUBLE) &&
  1660.            attrib(y, x+1, a) != attrib(y+1, x+1, a) )  redrawc(x+1, y);
  1661.  
  1662.      } /* if !protected */
  1663.  
  1664.      x++;
  1665.       }         /* while x<40 && (serialmode --> no marker set) */
  1666.       while(x<40  && (mode!=1 || !(screen[y][x].mark & mattr)) );
  1667.    }
  1668.    else {  /* parallel */
  1669.       switch(a) {
  1670.          case ATTR_NODOUBLE:
  1671.             t.par_attr &= ~(ATTR_XDOUBLE|ATTR_YDOUBLE);
  1672.         break;
  1673.      case ATTR_XYDOUBLE:
  1674.         t.par_attr |= (ATTR_XDOUBLE|ATTR_YDOUBLE);
  1675.         break;
  1676.      case ATTR_XDOUBLE:
  1677.         t.par_attr &= ~ATTR_YDOUBLE;
  1678.             t.par_attr |= ATTR_XDOUBLE;
  1679.         break;
  1680.      case ATTR_YDOUBLE:
  1681.         t.par_attr &= ~ATTR_XDOUBLE;
  1682.             t.par_attr |= ATTR_YDOUBLE;
  1683.         break;
  1684.          case ATTR_FOREGROUND:
  1685.         t.par_fg = col;
  1686.         break;
  1687.      case ATTR_BACKGROUND:
  1688.         t.par_bg = col;
  1689.         break;
  1690.      default:
  1691.         if(set)  t.par_attr |= a;
  1692.         else     t.par_attr &= ~a;
  1693.         break;
  1694.       }
  1695.    }
  1696. }
  1697.  
  1698.  
  1699. /*
  1700.  * output character c from current set at current cursor position.
  1701.  */
  1702.  
  1703. void BTXService::output(int c)
  1704. {
  1705.    int xd, yd, set, mattr, x = t.cursorx, y = t.cursory;
  1706.  
  1707.    /* select active character set */
  1708.    if(t.sshift) set = t.G0123L[ t.sshift ];
  1709.    else         set = t.G0123L[ t.leftright[ (c&0x80) >> 7 ] ];
  1710.  
  1711.    if(t.serialmode) {
  1712.       xd = attrib(y, x, ATTR_XDOUBLE);
  1713.       yd = attrib(y, x, ATTR_YDOUBLE);
  1714.  
  1715.       /* update screen memory (if not protected) */
  1716.       if( t.service_break || !attrib(y, x, ATTR_PROTECTED) ) {
  1717.      screen[y-1][x-1].chr = (unsigned short)(c & ~0x80);
  1718.      screen[y-1][x-1].set = (UBYTE)set;
  1719.      redrawc(x, y);
  1720.       }
  1721.    }
  1722.    else {  /* parallel */
  1723.       xd = (t.par_attr & ATTR_XDOUBLE) > 0;
  1724.       yd = (t.par_attr & ATTR_YDOUBLE) > 0;
  1725.       if(y<2)  yd = 0;
  1726.  
  1727.       /* if not protected, (scroll +) update memory */
  1728.       if( t.service_break || !attrib(y, x, ATTR_PROTECTED) ) {
  1729.  
  1730.  
  1731.  
  1732.      /* parallel DBS/DBH chars in first row of scrolling area          */
  1733.      /* force a scroll down + a cursor down before writing (page 101) */
  1734.      if(yd && t.scroll_area && y==t.scroll_upper) {
  1735.         scroll(0);
  1736.         move_cursor(APD);
  1737.         y = t.cursory;
  1738.      }
  1739.  
  1740.      /* update screen memory
  1741.       * if no DBS/DBH in the first row or in the row below a protected area
  1742.       * if no DBS/DBH in the row below a scrolling area (page 99)
  1743.       */
  1744.      if( !(yd && !t.service_break && attrib(y-1, x, ATTR_PROTECTED))  &&
  1745.         !(yd && t.scroll_area && y==t.scroll_lower+1)  ) {
  1746.  
  1747.         /* parallel DBH/DBS chars extent upwards, write in the row above */
  1748.         if(yd) y--;
  1749.  
  1750.         screen[y-1][x-1].chr  = (unsigned short)(c & ~0x80);
  1751.         screen[y-1][x-1].set  = (UBYTE)set;
  1752.         screen[y-1][x-1].fg   = (UBYTE)t.par_fg;
  1753.         screen[y-1][x-1].bg   = (UBYTE)t.par_bg;
  1754.         screen[y-1][x-1].attr = (unsigned short)t.par_attr;
  1755.  
  1756.         /* par. DBS/DBW attrs apply also to the next char ! (page 106) */
  1757.         if(xd && x<40)    screen[y-1][x].attr = (unsigned short)t.par_attr;
  1758.  
  1759.         mattr = t.par_attr & ~ATTR_ANYSIZE;
  1760.         if(t.par_attr & ATTR_ANYSIZE)  mattr |= ATTR_SIZE;
  1761.  
  1762.         if(x>1) {  /* set/reset markers */
  1763.            screen[y-1][x-1].mark = (unsigned short)(screen[y-1][x-1-1].attr ^ mattr);
  1764.            screen[y-1][x-1].mark &= ~(ATTR_FOREGROUND|ATTR_BACKGROUND);
  1765.            if(screen[y-1][x-1-1].fg!=t.par_fg)
  1766.               screen[y-1][x-1].mark |= ATTR_FOREGROUND;
  1767.            if(screen[y-1][x-1-1].bg!=t.par_bg)
  1768.               screen[y-1][x-1].mark |= ATTR_BACKGROUND;
  1769.         }
  1770.         if(x<40) {    /* set/reset markers */
  1771.            screen[y-1][x].mark = (unsigned short)(mattr ^ screen[y-1][x].attr);
  1772.            screen[y-1][x].mark &= ~(ATTR_FOREGROUND|ATTR_BACKGROUND);
  1773.            if(screen[y-1][x].fg!=t.par_fg)
  1774.               screen[y-1][x].mark |= ATTR_FOREGROUND;
  1775.            if(screen[y-1][x].bg!=t.par_bg)
  1776.               screen[y-1][x].mark |= ATTR_BACKGROUND;
  1777.         }
  1778.  
  1779.         redrawc(x, y);
  1780.      } /* scrolling/protected area */
  1781.       } /* if not protected */
  1782.    }  /* if serial / parallel */
  1783.  
  1784.    if(xd && t.cursorx<40)  move_cursor(APF);
  1785.    move_cursor(APF);
  1786.    t.sshift = 0;
  1787. }
  1788.  
  1789.  
  1790. /*
  1791.  * redraws character at screen position x, y (1 based !),
  1792.  * if not concealed or obscured
  1793.  */
  1794.  
  1795. void BTXService::redrawc(int x, int y)
  1796. {
  1797. //     extern int reveal;
  1798.    int c, set, xd, yd, up_in=0, dn_in=0;
  1799.    unsigned int real, xreal, yreal, xyreal;
  1800.  
  1801.       /* check whether attributes are valid */
  1802.       xd = attrib(y, x, ATTR_XDOUBLE);
  1803.       yd = attrib(y, x, ATTR_YDOUBLE);
  1804.       if(x>=40)    xd = 0;
  1805.       if(y>=rows)  yd = 0;
  1806.  
  1807.       /* check whether origin is obscured */
  1808.       if( (y>1 && realattr(y-1, x, ATTR_YDOUBLE)) ||
  1809.           (x>1 && realattr(y, x-1, ATTR_XDOUBLE)) ||
  1810.       (y>1 && x>1 && realattr(y-1, x-1, ATTR_XDOUBLE) &&
  1811.           realattr(y-1, x-1, ATTR_YDOUBLE)) ) {
  1812.      screen[y-1][x-1].real = 0;
  1813.       }
  1814.       else {
  1815.      /* check whether DBW char is partially obscured */
  1816.      if(xd && y>1 && x<40 && realattr(y-1, x+1, ATTR_YDOUBLE))    xd = 0;
  1817.  
  1818.      /* check whether char crosses borders of scrolling area (page 99) */
  1819.      if(yd && t.scroll_area) {
  1820.         if(y  >=t.scroll_upper && y  <=t.scroll_lower)    up_in=1;
  1821.         if(y+1>=t.scroll_upper && y+1<=t.scroll_lower)    dn_in=1;
  1822.         if(up_in != dn_in)    yd = 0;
  1823.      }
  1824.  
  1825.      /* check whether char crosses borders of protected area (page 110) */
  1826.      if(yd &&  attrib(y, x, ATTR_PROTECTED) !=
  1827.                attrib(y+1, x, ATTR_PROTECTED) )  yd=0;
  1828.  
  1829.      /* concealed characters are drawn as SPACES (page 109) */
  1830. //     if(!reveal && attrib(y, x, ATTR_CONCEALED)) { c=' ';    set=PRIM; }
  1831. //     else {
  1832.         c    = screen[y-1][x-1].chr & 0x7f;
  1833.         set = screen[y-1][x-1].set;
  1834. //     }
  1835.  
  1836.      /* now really display the character in the remaining size */
  1837.      AppDisplay->xputc(c, set, x-1, y-1, xd, yd,
  1838.            attrib(y, x, ATTR_UNDERLINE),
  1839.            (screen[y-1][x-1].chr>>8) & 0x7f,
  1840.            attrib(y, x, ATTR_INVERTED) ? attr_bg(y, x) : attr_fg(y, x),
  1841.            attrib(y, x, ATTR_INVERTED) ? attr_fg(y, x) : attr_bg(y, x) );
  1842.      if(t.cursor_on && x==t.cursorx && y==t.cursory)  AppDisplay->xcursor(x-1, y-1);
  1843.  
  1844.      /* update 'real' attributes */
  1845.      real = screen[y-1][x-1].real;
  1846.      screen[y-1][x-1].real = (unsigned short)(screen[y-1][x-1].attr & ~ATTR_ANYSIZE);
  1847.      if(xd) {
  1848.         screen[y-1][x-1].real |= ATTR_XDOUBLE;
  1849.         xreal = screen[y-1][x].real;
  1850.         screen[y-1][x].real = 0;
  1851.      }
  1852.      if(yd) {
  1853.         screen[y-1][x-1].real |= ATTR_YDOUBLE;
  1854.         yreal = screen[y][x-1].real;
  1855.         screen[y][x-1].real = 0;
  1856.      }
  1857.      if(xd && yd) {
  1858.         xyreal = screen[y][x].real;
  1859.         screen[y][x].real = 0;
  1860.      }
  1861.  
  1862.      /* redraw (indirect recursion !!) neighbours */
  1863.      updatec(real, x, y);
  1864.      if(xd)  updatec(xreal, x+1, y);
  1865.      if(yd)  updatec(yreal, x, y+1);
  1866.      if(xd && yd)  updatec(xyreal, x+1, y+1);
  1867.  
  1868.      /* redraw an enlarged char to the left (now partially obscured !) */
  1869.      if(yd && x>1 && realattr(y+1, x-1, ATTR_XDOUBLE))    redrawc(x-1, y+1);
  1870.       } /* origin obscured */
  1871. }
  1872.  
  1873.  
  1874. /*
  1875.  * this character has been obscured. check whether it was an enlarged char
  1876.  * and therefor its neighbours have to be redrawn.
  1877.  */
  1878. void BTXService::updatec(int real, int x, int y)
  1879. {
  1880.    if(real & ATTR_XDOUBLE)    redrawc(x+1, y);
  1881.    if(real & ATTR_YDOUBLE)    redrawc(x, y+1);
  1882.    if( (real & ATTR_XDOUBLE) && (real & ATTR_YDOUBLE) )  redrawc(x+1, y+1);
  1883. }
  1884.  
  1885.  
  1886. /*
  1887.  * redraw rectangle of screen (for exposure handling)
  1888.  */
  1889.  
  1890.  
  1891. void BTXService::redraw_screen_rect(int x1, int y1, int x2, int y2)
  1892. {
  1893.    int x, y;
  1894.  
  1895.    for(y=y1; y<=y2; y++)
  1896.       for(x=x1; x<=x2; x++)  redrawc(x+1, y+1);
  1897. }
  1898.  
  1899.  
  1900. /*
  1901.  * DRC's in the range start-stop with step have been (re)defined.
  1902.  * This routine checks whether this character is currently visible and so
  1903.  * needs to be redisplayed.
  1904.  */
  1905.  
  1906. void BTXService::update_DRCS_display(int start, int stop, int step)
  1907. {
  1908.    int x, y, c;
  1909.  
  1910.    for(y=0; y<24; y++)
  1911.       for(x=0; x<40; x++)
  1912.      if(screen[y][x].set==DRCS)
  1913.         for(c=start; c<stop; c+=step)
  1914.            if(screen[y][x].chr==c)    redrawc(x+1, y+1);
  1915. }
  1916.  
  1917.  
  1918. /*
  1919.  * initialize screen memory and clear display
  1920.  */
  1921.  
  1922. void BTXService::clearscreen()
  1923. {
  1924.    int x, y;
  1925.  
  1926.    t.clut = 0;
  1927.    t.par_attr = 0;
  1928.    t.par_fg = WHITE;
  1929.    t.par_bg = TRANSPARENT;
  1930.    t.scroll_area = 0;
  1931.    t.scroll_impl = 1;
  1932.    t.cursorx = t.cursory = 1;
  1933.  
  1934.    for(y=0; y<24; y++)
  1935.       for(x=0; x<40; x++) {
  1936.      screen[y][x].chr = ' ';
  1937.      screen[y][x].set = PRIM;
  1938.      screen[y][x].attr = 0;
  1939.      screen[y][x].real = 0;
  1940.      screen[y][x].mark = 0;
  1941.      screen[y][x].fg = WHITE;
  1942.      screen[y][x].bg = TRANSPARENT;
  1943.       }
  1944.  
  1945.    AppDisplay->xclearscreen();
  1946.    if(t.cursor_on) AppDisplay->xcursor(0, 0);
  1947. }
  1948.  
  1949. void BTXService::scroll(int up)
  1950. {
  1951.    int y, x, savereal[40];
  1952.  
  1953.    if(up) {
  1954.       /* save real attributes of first row */
  1955.       for(x=0; x<40; x++)  savereal[x] = screen[t.scroll_upper-1][x].real;
  1956.  
  1957.       /* scroll screen memory up */
  1958.       for(y=t.scroll_upper-1; y<t.scroll_lower-1; y++) {
  1959.      for(x=0; x<40; x++)  screen[y][x] = screen[y+1][x];
  1960.       }
  1961.    }
  1962.    else {
  1963.       /* scroll screen memory down */
  1964.       for(y=t.scroll_lower-1; y>t.scroll_upper-1; y--) {
  1965.      for(x=0; x<40; x++)  screen[y][x] = screen[y-1][x];
  1966.       }
  1967.    }
  1968.  
  1969.    /* clear row */
  1970.    for(x=0; x<40; x++) {
  1971.       screen[y][x].chr = ' ';
  1972.       screen[y][x].set = PRIM;
  1973.       screen[y][x].attr = 0;
  1974.       screen[y][x].real = 0;
  1975.       screen[y][x].mark = 0;
  1976.       screen[y][x].fg = WHITE;
  1977.       screen[y][x].bg = TRANSPARENT;
  1978.    }
  1979.  
  1980.    /* fast scroll the area */
  1981.    for(y=t.scroll_upper; y<=t.scroll_lower; y++)
  1982.       for(x=1; x<=40; x++)    redrawc(x, y);
  1983.  
  1984.    /* redraw cursor */
  1985.    if(t.cursor_on && t.cursory>=t.scroll_upper && t.cursory<=t.scroll_lower)
  1986.       AppDisplay->xcursor(t.cursorx-1, t.cursory-1);
  1987. }
  1988.  
  1989. void BTXService::do_Telesoftware(void)
  1990. {
  1991.     int c,i,j,len,total,size,temp;
  1992.     UBYTE *data,*final;
  1993.  
  1994.     c = layer2getc();
  1995.  
  1996.     if(reachedEOF)
  1997.         return;
  1998.  
  1999.     switch(c)
  2000.     {
  2001.         case 0x27:            // D-Set mode, A7.4, p5
  2002.  
  2003.             for(i = 0 ; i < 4 ; i++)
  2004.                 layer2getc();
  2005.  
  2006.             c = layer2getc();
  2007.  
  2008.             if(reachedEOF)
  2009.                 return;
  2010.  
  2011.             telemode = MODE_Unknown;
  2012.  
  2013.             if(c == 0x42)
  2014.                 telemode = MODE_3in4;
  2015.  
  2016.             if(c == 0x41)
  2017.                 telemode = MODE_8Bit;
  2018.  
  2019.             telesequence = 0x41;
  2020.  
  2021.             LOG(("d-set mode, mode = %ld\n",telemode));
  2022.  
  2023.             break;
  2024.  
  2025.         case 0x33:            // D-End group, A7.4, p6
  2026.  
  2027.             LOG(("d-end group\n"));
  2028.  
  2029.             if(telefile)
  2030.             {
  2031.                 fclose(telefile);
  2032.                 telefile = NULL;
  2033.             }
  2034.  
  2035.             telemode = MODE_Unknown;
  2036.  
  2037.             teledownload = FALSE;
  2038.  
  2039.             telename[0] = 0;
  2040.  
  2041.             break;
  2042.  
  2043.         default:            // D-Data, A7.4, p3
  2044.  
  2045.             telesequence = c;
  2046.  
  2047.             LOG(("sequence code 0x%02lx\n",c));
  2048.  
  2049.             if(telemode != MODE_3in4)    // Hier ist nur 3in4 zugelassen
  2050.                 break;
  2051.  
  2052.             total = 0;
  2053.  
  2054.             for(;;)
  2055.             {
  2056.                 c = layer2getc();
  2057.  
  2058.                 if(reachedEOF)
  2059.                     return;
  2060.                 else
  2061.                 {
  2062.                     if(c == US)
  2063.                     {
  2064.                         layer2ungetc(c);
  2065.                         break;
  2066.                     }
  2067.                     else
  2068.                         telebuffer[total++] = (UBYTE)c;
  2069.                 }
  2070.             }
  2071.  
  2072.             len        = decode_3in4(telebuffer,telebuffer,total);
  2073.             data    = telebuffer;
  2074.  
  2075.             while(len > 0)
  2076.             {
  2077.                 switch(*data)
  2078.                 {
  2079.                     case 0x23:            // T-Associate, A7.4, p7
  2080.  
  2081.                         len--;
  2082.                         data++;
  2083.  
  2084.                         LOG(("t-associate\n"));
  2085.  
  2086.                         teledownload = TRUE;
  2087.  
  2088.                         len--;
  2089.                         size = *data++;
  2090.  
  2091.                         len -= size;
  2092.                         data += size;
  2093.  
  2094.                         break;
  2095.  
  2096.                     case 0x63:            // T-Filespec, A7.4, p9
  2097.  
  2098.                         len--;
  2099.                         data++;
  2100.  
  2101.                         LOG(("t-filespec\n"));
  2102.  
  2103.                         len--;
  2104.                         size = *data++;
  2105.                         final = data + size;
  2106.                         len -= size;
  2107.  
  2108.                         data++;
  2109.                         size--;
  2110.  
  2111.                         while(size > 0)
  2112.                         {
  2113.                             c = *data++;
  2114.                             size--;
  2115.  
  2116.                             switch(c)
  2117.                             {
  2118.                                 case 0x65:        // Filename
  2119.  
  2120.                                     total = *data++;
  2121.                                     size--;
  2122.  
  2123.                                     for(j = 0 ; j < total ; j++)
  2124.                                     {
  2125.                                         telename[j] = (char)*data++;
  2126.                                         size--;
  2127.                                     }
  2128.  
  2129.                                     telename[j] = 0;
  2130.  
  2131.                                     LOG(("filename |%s|\n",telename));
  2132.  
  2133.                                     break;
  2134.  
  2135.                                 case 0x7F:        // Date/time
  2136.  
  2137.                                     total = *data++;
  2138.                                     size--;
  2139.  
  2140.                                     for(j = 0 ; j < total ; j++)
  2141.                                     {
  2142.                                         teledate[j] = (char)*data++;
  2143.                                         size--;
  2144.                                     }
  2145.  
  2146.                                     teledate[j] = 0;
  2147.  
  2148.                                     LOG(("date |%s|\n",teledate));
  2149.  
  2150.                                     break;
  2151.  
  2152.                                 case 0x67:        // File length
  2153.  
  2154.                                     total = *data++;
  2155.                                     size--;
  2156.  
  2157.                                     temp = 0;
  2158.  
  2159.                                     for(j = 0 ; j < total ; j++)
  2160.                                     {
  2161.                                         temp = (temp * 256) + (*data++);
  2162.                                         size--;
  2163.                                     }
  2164.  
  2165.                                     telesize = temp;
  2166.  
  2167.                                     LOG(("size %ld\n",temp));
  2168.  
  2169.                                     break;
  2170.  
  2171.                                 default:        // Was auch immer...
  2172.  
  2173.                                     total = *data++;
  2174.                                     size--;
  2175.  
  2176.                                     data += total;
  2177.                                     size -= total;
  2178.                                     break;
  2179.                             }
  2180.                         }
  2181.  
  2182.                         data = final;
  2183.  
  2184.                         break;
  2185.  
  2186.                     case 0x43:    // T-Write-Start, A7.4, p10
  2187.  
  2188.                         len--;
  2189.                         data++;
  2190.  
  2191.                         LOG(("t-write-start\n"));
  2192.  
  2193.                         len--;
  2194.                         size = *data++;
  2195.  
  2196.                         len -= size;
  2197.                         data += size;
  2198.  
  2199.                         if(telefile)
  2200.                         {
  2201.                             fclose(telefile);
  2202.                             telefile = NULL;
  2203.                         }
  2204.  
  2205.                         if(!telefile && teledownload)
  2206.                         {
  2207.                             if(telename[0])
  2208.                                 telefile = fopen((const char *)telename,"wb");
  2209.                             else
  2210.                                 telefile = fopen((const char *)"telesoftware","wb");
  2211.                         }
  2212.  
  2213.                         if(len)
  2214.                         {
  2215.                             LOG(("\t%ld bytes in this block\n",len));
  2216.  
  2217.                             if(telefile)
  2218.                             {
  2219.                                 if(fwrite(data,len,1,telefile) != 1)
  2220.                                     return;
  2221.                             }
  2222.  
  2223.                             len = 0;
  2224.                         }
  2225.  
  2226.                         break;
  2227.  
  2228.                     case 0x45:    // T-Write, A7.4, p11
  2229.  
  2230.                         len--;
  2231.                         data++;
  2232.  
  2233.                         LOG(("t-write\n"));
  2234.  
  2235.                         len--;
  2236.                         size = *data++;
  2237.  
  2238.                         len -= size;
  2239.                         data += size;
  2240.  
  2241.                         if(len)
  2242.                         {
  2243.                             LOG(("\t%ld bytes in this block\n",len));
  2244.  
  2245.                             if(telefile)
  2246.                             {
  2247.                                 if(fwrite(data,len,1,telefile) != 1)
  2248.                                     return;
  2249.                             }
  2250.  
  2251.                             len = 0;
  2252.                         }
  2253.  
  2254.                         break;
  2255.  
  2256.                     case 0x47:    // T-Write-End, A7.4, p11
  2257.  
  2258.                         len--;
  2259.                         data++;
  2260.  
  2261.                         LOG(("t-write-end\n"));
  2262.  
  2263.                         len--;
  2264.                         size = *data++;
  2265.  
  2266.                         len -= size;
  2267.                         data += size;
  2268.  
  2269.                         if(len)
  2270.                         {
  2271.                             LOG(("\t%ld bytes in this block\n",len));
  2272.  
  2273.                             if(telefile)
  2274.                             {
  2275.                                 if(fwrite(data,len,1,telefile) != 1)
  2276.                                     return;
  2277.                             }
  2278.  
  2279.  
  2280.                             len = 0;
  2281.                         }
  2282.  
  2283.                         if(telefile)
  2284.                         {
  2285.                             fclose(telefile);
  2286.                             telefile = NULL;
  2287.                         }
  2288.  
  2289.                         break;
  2290.  
  2291.                     default:
  2292.  
  2293.                         LOG(("unknown sequence 0x%02lx\n",c));
  2294.  
  2295.                         len--;
  2296.                         data++;
  2297.  
  2298.                         len--;
  2299.                         size = *data++;
  2300.  
  2301.                         len -= size;
  2302.                         data += size;
  2303.  
  2304.                         break;
  2305.                 }
  2306.             }
  2307.  
  2308.             break;
  2309.     }
  2310. }
  2311.  
  2312. void BTXService::write(const UBYTE *what,int len)
  2313. {
  2314.     App->AppChannel->PutString((CONST STRPTR)what,len);
  2315. }
  2316.  
  2317. int BTXService::decode_3in4(const UBYTE *data,UBYTE *out,int total)
  2318. {
  2319.     UBYTE buf[4];
  2320.     int len,eaten,done = 0;
  2321.  
  2322.     while(total > 0)
  2323.     {
  2324.         if(total == 2)
  2325.         {
  2326.             buf[0] = (UBYTE)(((data[0] & 0x30) << 2) | (data[1] & 0x3f));
  2327.             len = 1;
  2328.             eaten = 2;
  2329.         }
  2330.         else
  2331.         {
  2332.             if(total == 3)
  2333.             {
  2334.                 buf[0] = (UBYTE)(((data[0] & 0x30) << 2) | (data[1] & 0x3f));
  2335.                 buf[1] = (UBYTE)(((data[0] & 0x0c) << 4) | (data[2] & 0x3f));
  2336.                 len = 2;
  2337.                 eaten = 3;
  2338.             }
  2339.             else
  2340.             {
  2341.                 if(total >= 4)
  2342.                 {
  2343.                     buf[0] = (UBYTE)(((data[0] & 0x30) << 2) | (data[1] & 0x3f));
  2344.                     buf[1] = (UBYTE)(((data[0] & 0x0c) << 4) | (data[2] & 0x3f));
  2345.                     buf[2] = (UBYTE)(((data[0] & 0x03) << 6) | (data[3] & 0x3f));
  2346.                     len = 3;
  2347.                     eaten = 4;
  2348.                 }
  2349.                 else
  2350.                     break;
  2351.             }
  2352.         }
  2353.  
  2354.         memcpy(out,buf,len);
  2355.  
  2356.         total -= eaten;
  2357.         data += eaten;
  2358.  
  2359.         out += len;
  2360.         done += len;
  2361.     }
  2362.  
  2363.     return(done);
  2364. }
  2365.